#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>

#include "epub.h"



/*
 * returns zero on success, or -1 if an error occurred
 */
int create_folder()//TODO decidir directorio donde meter el resultado
{
	
	return (mkdir("epub_FILES",0777) 	|
	mkdir("epub_FILES/META-INF",0777)	|
	mkdir("epub_FILES/OEBPS",0777)		|
	mkdir("epub_FILES/OEBPS/Text",0777)	|
	mkdir("epub_FILES/OEBPS/Styles",0777)	|	
	mkdir("epub_FILES/OEBPS/Images",0777) );
}



int exec(char *cmd, char **params)
{
	int pid;

    if ((pid = fork()) == -1){
        perror("fork error");
        return -1;
    }
    else if (pid == 0) 
    	if (execv(cmd, params) == -1){
    		printf("ERROR: execv error in command: %s\n", cmd);
    		return -1;
    	}	

	waitpid(pid, NULL, 0);
	return 0;    		
}


int cp_aux_files()
{
	char *cmd = {"/bin/cp"};
	char *params1[] = {"/bin/cp", "-R", "./auxfiles/mimetype", 
					   "./epub_FILES/mimetype", NULL};
	char *params2[] = {"/bin/cp", "-R", "./auxfiles/META-INF/container.xml",
					   "./epub_FILES/META-INF/container.xml", NULL};
	char *params3[] = {"/bin/cp", "-R", "./auxfiles/OEBPS/Styles/style.css", 
					   "./epub_FILES/OEBPS/Styles/style.css", NULL};

    return (exec(cmd, params1) |
			exec(cmd, params2) |
			exec(cmd, params3));

}

int fill_content(char *title, int fd_content)
{
	char *part_a = {"<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\"?> \
		<package xmlns=\"http://www.idpf.org/2007/opf\" unique-identifier=\"BookId\" version=\"2.0\"> \
		<metadata xmlns:dc=\"http://purl.org/dc/elements/1.1/\" xmlns:opf=\"http://www.idpf.org/2007/opf\"> \
		<dc:identifier id=\"BookId\">awp2011-04-02T17:17:45Z</dc:identifier> \
    	<dc:title>"};

    char *part_b = {"</dc:title> \
    	<dc:subject>Wikipedia</dc:subject> \
    	<dc:creator opf:role=\"aut\">David y Eugenio</dc:creator> \
		<dc:description>Articulo Wikipedia</dc:description>\
		<dc:date opf:event=\"publication\">1999-01-01</dc:date>\
		<dc:language>es</dc:language>\
		<meta content=\"cover\" name=\"cover\" />\
		<meta content=\"0.4.0\" name=\"Sigil version\" />\
		</metadata>\
		<manifest>\
		<item href=\"toc.ncx\" id=\"ncx\" media-type=\"application/x-dtbncx+xml\" />\
		<item href=\"Styles/style.css\" id=\"style\" media-type=\"text/css\" />"};

	if( (write(fd_content, part_a, strlen(part_a)) == -1)
			|| ( write(fd_content, title, strlen(title)) == -1)
			|| ( write(fd_content, part_b, strlen(part_b)) == -1) )
		return -1;
	return 0;
}

int fill_toc(char *title, int fd_toc)
{
	char *part_a = {"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\" ?> \
		<!DOCTYPE ncx PUBLIC \"-//NISO//DTD ncx 2005-1//EN\" \"http://www.daisy.org/z3986/2005/ncx-2005-1.dtd\"> \
		<ncx xmlns=\"http://www.daisy.org/z3986/2005/ncx/\" version=\"2005-1\"> \
		<head> \
		<meta content=\"awp2011-04-02T17:17:45Z\" name=\"dtb:uid\"/> \
		<meta content=\"2\" name=\"dtb:depth\"/> \
		<meta content=\"0\" name=\"dtb:totalPageCount\"/> \
		<meta content=\"0\" name=\"dtb:maxPageNumber\"/> \
		</head> \
		<docTitle> \
		<text>"};

	char *part_b = {"</text> \
		</docTitle> \
		<navMap>"};

	if ((write(fd_toc, part_a, strlen(part_a)) == -1)
			|| (write(fd_toc, title, strlen(title)) == -1)
			|| (write(fd_toc, part_b, strlen(part_b)) == -1) )
		return -1;
	return 0;
}

int create_files(char * title, int *fd_content, int *fd_toc)
{
	int flgs = O_CREAT|O_WRONLY|O_TRUNC;

	if(((*fd_content) = open("epub_FILES/OEBPS/content.opf",flgs, 0777)) == -1){
		perror("Imposible crear content.opf");
		return -1;
	}

	if(((*fd_toc) = open("epub_FILES/OEBPS/toc.ncx",flgs, 0777)) == -1){
		perror("Imposible crear toc.ncx");
		return -1;
	}

	if(fill_content(title, *fd_content) == -1){
		perror("Error al escribir en content.opf");
		return -1;
	}

	if(fill_toc(title, *fd_toc) == -1){
		perror("Error al escribir en content.opf");
		return -1;
	}

}

int fill_chapter(chapter *chap, int fd_chapter)
{
	char *head = {"<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"no\"?> \
		<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\" \
		\"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\"> \
		<html xmlns=\"http://www.w3.org/1999/xhtml\"> \
		<head> \
		<link href=\"../Styles/style.css\" rel=\"stylesheet\" type=\"text/css\" /> \
		<title>"};

	char *head2 = {"</title> \
		</head> \
		<body style=\"\"> \
		<h1 id=\"heading_id_2\">"};
	char *h = {"</h1>"};

	if (write(fd_chapter, head, strlen(head)) == -1)
		return -1;
	if((chap->title) != NULL){
		if (write(fd_chapter, chap->title , strlen(chap->title)) == -1)
			return -1;
	}
	if (write(fd_chapter, head2, strlen(head2)) == -1)
		return -1;
	if((chap->title) != NULL){
		if (write(fd_chapter, chap->title , strlen(chap->title)) == -1)
			return -1;
	}
	if (write(fd_chapter, h, strlen(h)) == -1)
		return -1;
}

int fill_chapter_content(lista content, int fd_chapter)
{
	nodo *n;
	char *aux;
	char *i_p = {"<p>"};
	char *f_p = {"</p>"};

	if (content == NULL)
		return 0;
	
	n = get_ultimo(&content);

	while(n != NULL){
		aux = (char *)n->datos;
		if(aux != NULL){
			if ((write(fd_chapter, i_p, strlen(i_p)) == -1)
					|| (write(fd_chapter, aux, strlen(aux)) == -1)
					|| (write(fd_chapter, f_p, strlen(f_p)) == -1) )
				return -1;
		}
		n = anterior(n);
	}
}

int make_chapter(chapter *chap, char *name)
{
	char path[32];
	int fd_chapter;
	int flgs = O_CREAT|O_WRONLY|O_TRUNC;
	char *close_chapter = {"</body> </html>"};

	if(sprintf(path, "epub_FILES/OEBPS/Text/%s", name) < 0){
		perror("No se puede formar el path");
		return -1;
	}

	if((fd_chapter = open(path,flgs, 0777)) == -1){
		perror("Imposible crear chapter.xhtml");
		return -1;
	}

	if (fill_chapter(chap, fd_chapter) == -1)
		return -1;

	if(fill_chapter_content(chap->content, fd_chapter) == -1)
		return -1;

	if (write(fd_chapter, close_chapter, strlen(close_chapter)) == -1)
		return -1;

	close(fd_chapter);
}

int write_chapter_content(int fd_content, char *name)
{
	char item[90];

	if(sprintf(item,
			"<item href=\"Text/%s\" id=\"x%s\" media-type=\"application/xhtml+xml\" />", name, name) < 0){
		perror("No se puede construir item");
		return -1;
	}
		

	if (write(fd_content, item, strlen(item)) == -1){
		perror("No se puede escribir el item");
		return -1;
	}

}
int write_chapter_toc(int fd_toc, char *name, char *title, int num_chapter)
{
    char nav_point[200];

	if(sprintf(nav_point,
			"<navPoint id=\"navPoint-%d\" playOrder=\"%d\"> \
			<navLabel> \
			<text>%s</text> \
			</navLabel> \
			<content src=\"Text/%s\"/> \
			</navPoint>", num_chapter, num_chapter, title, name) < 0){

		perror("No se puede construir navPoint");
		return -1;
	}

	if (write(fd_toc, nav_point, strlen(nav_point)) == -1){
		perror("No se puede escribir el navPoint");
		return -1;
	}

}

int mk_articles(lista epub, int fd_content, int fd_toc)
{
	int num_chapter = 0;
	nodo *n;
	chapter *aux;
	char name[10];
	char *close_toc = {"</navMap> </ncx>"};
	n = get_ultimo(&epub);

	while(n != NULL){
		num_chapter++;
		aux = (chapter *)n->datos;
		
		if(sprintf(name, "%03d.xhtml", num_chapter) < 0)
			return -1;
		
		if (make_chapter(aux, name) == -1)
			return -1;

		if(write_chapter_content(fd_content, name) == -1)
			return -1;

		if(write_chapter_toc(fd_toc, name, aux->title, num_chapter) == -1)
			return -1;

		n = anterior(n);
	}

	if (write(fd_toc, close_toc, strlen(close_toc)) == -1){
		perror("No se puede cerrar los tags en toc.ncx");
		return -1;
	}
	
	close(fd_toc);

	return num_chapter;
}


int download_image(char *img)
{
	int pid;

	char *cmd = {"get_image.sh"};
	char *params[3];
	params[0] = cmd;
	params[1] = img;
	params[2] = NULL;

    if ((pid = fork()) == -1){
        perror("fork error");
        return -1;
    }
    else if (pid == 0) 
    	if (execv(cmd, params) == -1){
    		perror("execv error");
    		return -1;
    	}	

    //Wait while image dowload.Some big images could take a long time
	waitpid(pid, NULL, 0);
	return 0;    
}

// img18.jpg
int write_img_toc(char *img, int fd)
{
	char *part_a = {"<item href=\"Images/"};
	char *part_b = {"\" id=\"img18\" media-type=\"image/jpeg\" />"};

	if ((write(fd, part_a, strlen(part_a))) == -1 
		||	(write(fd, img, strlen(img)) == -1)
		||  (write(fd, part_b, strlen(part_b)) == -1) )

		return -1;

	return 0;
}
    
int close_man_tag(int fd)
{
	char *ctag = {"</manifest>"};

	if (write(fd, ctag, strlen(ctag)) == -1)
		return -1;
}   

/*
 * Download all images
 * l_img = list of string
 */
int mk_images(lista l_img, int fd_content)
{
	nodo *n;
	int pid;
	char *img_name;

	if (l_img == NULL){
		if(close_man_tag(fd_content) == -1)
		return -1;	
		return 0;
	}

	n = get_ultimo(&l_img);
	
	while(n != NULL){
		img_name = (char *)get_datos(n);

		printf("\tDownloading image: %s ", img_name);
		fflush(stdout);
	    
	    if(download_image(img_name) == -1){
	    	printf("[FAIL]\n");
	    	return -1;
	    }

		if(write_img_toc(img_name, fd_content) == -1)
			return -1;
	    
	    printf("[COMPLETED]\n");			    
	    fflush(stdout);
	    n = anterior(n);   		
	}
	//Close <manifest> in close_content_opf()
	if(close_man_tag(fd_content) == -1)
		return -1;	

	return 0;  
}


int close_content_opf(int fd, int num_chapter)
{
	int i;
	char nchapter[50];
	//Do spine
	char *ospine = {"<spine toc=\"ncx\">"};
	char *cspine = {"</spine> </package>"};	
	
	if(write(fd, ospine, strlen(ospine)) == -1)
		return -1;

	for(i=1; i<=num_chapter; i++){
		sprintf(nchapter, "<itemref idref=\"x%03d.xhtml\" />", i);
		if(write(fd, nchapter, strlen(nchapter)) == -1)
			return -1;		
	}

	if(write(fd, cspine, strlen(cspine)) == -1)
		return -1;		

	close(fd);	
	return 0;		
 }


/*
 *MAKING EPUB  
 *
 * $zip -X0 EpubGuide-hxa7241.epub mimetype
 * $zip -Xur9D EpubGuide-hxa7241.epub META-INF OEBPS
 */
int make_epub(char *title)
{

	char *epub_title;	
	char *cmd = {"/usr/bin/zip"};
	char *param1_1 ={"-X0"};
	char *param2_1 ={"-Xur9D"};
	char *mimetype ={"mimetype"};
	char *metainf ={"META-INF"};
	char *oebps ={"OEBPS"};

//	char *params1[] = {"/usr/bin/zip", "-X0", "../libro.epub", "mimetype", NULL};
//	char *params2[] = {"/usr/bin/zip", "-Xur9D", "../libro.epub", "META-INF", "OEBPS", NULL};

	char *params1[5];
	char *params2[6];

	epub_title = (char *) malloc((sizeof(char) * strlen(title)) + 9); // ../titulo.epub
	epub_title[0] = '\0';
	strcat(epub_title, "../output/");
	strcat(epub_title, title);	
	strcat(epub_title, ".epub");

	params1[0] = cmd;
	params1[1] = param1_1;
	params1[2] = epub_title;
	params1[3] = mimetype;
	params1[4] = NULL;

	params2[0] = cmd;
	params2[1] = param2_1;
	params2[2] = epub_title;
	params2[3] = metainf;
	params2[4] = oebps;
	params2[5] = NULL;

	chdir("epub_FILES");
// printf("TITULO: %s\n", title);
// printf("EXEC1: [%s][%s][%s][%s][%s]\n", params1[0],params1[1],params1[2],params1[3],params1[4]);
// printf("EXEC2: [%s][%s][%s][%s][%s][%s]\n", params2[0],params2[1],params2[2],params2[3],params2[4],params2[5]);
    exec(cmd, params1);
	exec(cmd, params2);
}


int create_epub(lista epub, lista l_img, char *title)
{
	
	int fd_content;
	int fd_toc;
	int num_chapter;

	//after create_folder if errno = EEXIST (file exists)
	//the error of create_folder is not an error for us, program should still running
	if ((create_folder(title) == -1) && (errno != EEXIST))
		return -1;	

	if (cp_aux_files() == -1)
		return -1;

	printf("Creating files: "); fflush(stdout);
	if (create_files(title, &fd_content, &fd_toc) == -1)
	 	return -1;
	printf("[COMPLETED]\n"); fflush(stdout);

	printf("Building chapters: "); fflush(stdout);
	if((num_chapter = mk_articles(epub, fd_content, fd_toc)) == -1){
		perror("ERROR: Imposible to generate articles");
		return -1;
	}
	printf("[COMPLETED]\n"); fflush(stdout);
	
	printf("Building images: \n"); fflush(stdout);
	if(mk_images(l_img, fd_content) == -1){
		perror("ERROR: Imposible download images");
		return -1;
	}
	printf("[COMPLETED]\n"); fflush(stdout);
	
	close_content_opf(fd_content, num_chapter);

	printf("Making epub: \n"); 
	if (make_epub(title) == -1){
		perror("ERROR: Imposible making epub file");
		return -1;
	}	
	printf("[COMPLETED]\n");	
}
